package gomz;

import gomz.res.*;
import gomz.res.Message.ActionTyp;

import java.net.Socket;
import java.util.ArrayList;


/**
 * Diese Klasse wird verwendet um vom Client zum Server ein Verbindung herzustellen
 * Ausserdem verwendet diese Klasse die Message Klasse um Nachrichten zu senden und zu Empfangen
 * @author Schatzmann
 * @author Murillo
 */ 
public class ClientToServerCon {
// ********************************************************************************
// Variablen
// ********************************************************************************
    //IP des zu verbindenden Servers
    private String ip;
    //Port des zu verbindenden Servers
    private int port;
    //Socket welcher automatisch im Konstruktor aus der IP und dem Port erzeugt wird
    private Socket client;

// ********************************************************************************
// Getter/Setter
// ********************************************************************************
    public Socket getClient() {
        return client;
    }

    public void setClient(Socket client) {
        this.client = client;
    }

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

// ********************************************************************************
// Konstruktor
// ********************************************************************************
    public ClientToServerCon(){
    	 this.ip = "127.0.0.1";
         this.port = 123;
         try{
	         Socket s = new Socket(ip, port);
	         this.client = s;
         }
         catch (Exception e){
        	 //TODO
         }
    }
    
    public ClientToServerCon(String ip, int port) throws Exception {
        this.ip = ip;
        this.port = port;
        //erzeugen des Sockets aus den Parametern IP und Port
        Socket s = new Socket(ip, port);
        this.client = s;
    }    
        
// ********************************************************************************
// Methoden
// ********************************************************************************
    
    /**
    * Diese Methode wird vom MLogin aufgerufen um eine Verbindung zum Server zu erstellen und den User einzulogen
    * Setzt den ActiveUser in den GlobalRes
    * @author Schatzmann
    * @param userCore enthaelt den Usernamen und das Password, mit diesem wird ein Login versuch gestartet
    * @return boolean answer, ob login erfolgreich(true) oder nicht (false)
    * @throws nichts
    */
    public boolean login(UserCore userCore){
        //GlobalRes zuruecksetzen
        GlobalRes.setActivUser(null);
        
        //***Variablen***
            //rueckgabewert answer standardmaessig auf false
            boolean answer = false;
            //msgOut: Nachricht welche an den Server gesendet werden soll
            Message msgOut;
            //msgIn: Nachricht welche vom Server erhalten wird
            Message msgIn;

        //neue Message erzeugen
        msgOut = new Message(Message.ActionTyp.Login);
        ArrayList<UserCore> arrayList = new ArrayList<UserCore>();
        arrayList.add(userCore);
        msgOut.setUserCoreCollection(arrayList);
        //ObjTyp.UserCore wird automatisch im setUserCoreCollection gesetzt
        
        
        //****SENDEN****
        //senden der msgOut an den Server
        try{
            //Verwenden der gespeicherten Verbindung: globalres.con.getClient()
            msgOut.send(this.getClient());
          
        }
        catch(Exception err){
            answer = false;
        }
        
        //****Empfangen**
        //Empfangen der Antwort vom Server in msgIn
        try{
             //abwarten der Antwort vom Server
             msgIn = Message.receive(this.getClient());              
             //ueberpruefen der antwort ob login erfolgreich war
             if (msgIn.getActionTyp() == ActionTyp.Success){
                 answer = true;
                 //MsgIn enthaelt alle Angaben des Users; User in GlobalRes setzen
                 GlobalRes.setActivUser(msgIn.getUser());
             }
             else{
                 answer = false;
                 GlobalRes.setActivUser(null);
             }   
        }
        catch(Exception err){
            answer = false;
        }
       
        //Rueckgabewert liefern: true = erfolgreich eingelogt; false = fehlgeschlagen
        return answer;

    }
        /**
    * Diese Methode wird vom MLogin aufgerufen um die Verbindung zum Server zu trennen und den User auszulogen
    * Setzt den ActiveUser und die Con in den GlobalRes zurueck
    * @author Schatzmann
    * @return boolean answer, ob logout erfolgreich(true) oder nicht (false)
    */
    public boolean logout(){  
        //***Variablen***
            //rueckgabewert answer standardmaessig auf false
            boolean answer = false;
            //msgOut: Nachricht welche an den Server gesendet werden soll
            Message msgOut;
            //msgIn: Nachricht welche vom Server erhalten wird
            Message msgIn;

        //neue Message erzeugen
        msgOut = new Message(Message.ActionTyp.Logout);
        msgOut.setUser(GlobalRes.getActivUser());
        //ObjTyp.User wird automatisch im setUser gesetzt
        
        
        //****SENDEN****
        //senden der msgOut an den Server
        try{
            //Verwenden der gespeicherten Verbindung: globalres.con.getClient()
            msgOut.send(this.getClient());
          
        }
        catch(Exception err){
            answer = false;
        }
        
        //****Empfangen**
        //Empfangen der Antwort vom Server in msgIn
        try{
             //abwarten der Antwort vom Server
             msgIn = Message.receive(this.getClient());              
             //ueberpruefen der antwort ob login erfolgreich war
             if (msgIn.getActionTyp() == ActionTyp.Success){
                 answer = true;
                 //GlobalRes zuruecksetzen
                 GlobalRes.setActivUser(null);
                 GlobalRes.setCon(null);
             }
             else{
                 answer = false;
             }   
        }
        catch(Exception err){
            answer = false;
        }
       
        //Rueckgabewert liefern: true = erfolgreich ausgelogt; false = fehlgeschlagen
        return answer;

    }
    
    //Author Murillo
    /**
     * Diese Methode hohlt hohlt alle QuestionCores vom Server, die dem Benutzer angezeigt werden sollen
     * Falls die QuestionCores nicht gehohlt werden konnten, wird NULL zurueckgegeben
     * @return ArrayList<QuestionCore> Alle QuestionCores, die der Benutzer einsehen kann
     */
    public ArrayList<QuestionCore> questionCoreGet(){
    	ArrayList<QuestionCore> questionCol = null;
    	//Senden
    	Message msgOut = new Message(Message.ActionTyp.GetAll);
    	msgOut.setObjectTyp(Message.ObjectTyp.QuestionCore);
    	try {
			msgOut.send(this.client);
		} catch (Exception e) {
			return (null);
		}
    	//Antwort
    	Message msgIn;
    	try {
			msgIn = Message.receive(this.client);
		} catch (Exception e) {
			return(null);
		}
    	if(msgIn.getActionTyp() == Message.ActionTyp.Success){
    		questionCol = msgIn.getQuestionCoreCollection();
    	}
    	else{
    		questionCol = null;
    	}
    	
        return (questionCol);
    }
   
    
    //Author Murillo
    /**
     * Diese Methode schickt die uebergebene Fragestellung an den Server mit der Anweisung diese zu speichern
     * Falls die Fragestellung auf dem Server nicht gespeichert werden konnte, wird NULL zurueckgegeben
     * @param question Die zu speichernde Fragestellung
     * @return Die gespeicherte Fragestellung (Falls sie noch keine ID hatte, besitzt sie nun eine) bzw. NULL
     */
    public Question questionSave(Question question){
    	Question re = null;
    	//Senden
    	Message msgOut = new Message(Message.ActionTyp.Save);
    	msgOut.setQuestion(question);
    	try {
			msgOut.send(this.client);
		} catch (Exception e) {
			return (null);
		}
    	//Antwort
    	Message msgIn;
    	try {
			msgIn = Message.receive(this.client);
		} catch (Exception e) {
			return(null);
		}
    	if(msgIn.getActionTyp() == Message.ActionTyp.Success)	re = msgIn.getQuestion();
    	else													re = null;
    	
        return (re);
    }
    
    //Author Murillo
    /**
     * Diese Methode hohlt eine Fragestellung vom server. Falls die Frage nicht abgerufen werden konnte, wird NULL zurueckgegeben.
     * @param id Die ID der zu hohlenden Fragestellung
     * @return Die gewuenschte Fragestellung bzw. NULL
     */
    public Question questionGet(int id){
    	//Senden
    	Message msgOut = new Message(Message.ActionTyp.Get);
    	Question neededQuestion = new Question();
    	neededQuestion.setId(id);
    	msgOut.setQuestion(neededQuestion);
    	try {
			msgOut.send(this.client);
		} catch (Exception e) {
			return (null);
		}
    	//Antwort
    	Message msgIn;
    	try {
			msgIn = Message.receive(this.client);
		} catch (Exception e) {
			return(null);
		}
    	if(msgIn.getActionTyp() == Message.ActionTyp.Success){
    		neededQuestion = msgIn.getQuestion();
    	}
    	else{
    		neededQuestion = null;
    	}
    	
        return (neededQuestion);
    }
    
    //Author Murillo
    /**
     * Diese Methode schickt dem Server die ID einer Fragestellung mit der Aufforderung diese zu loeschen
     * @param id ID der zu loeschenden Fragestellung
     * @return Boolean ob die Loeschung durchgefuehrt werden konnte
     */
    public boolean questionDelete(int id){
    	boolean re = true;
    	//Senden
    	Message msgOut = new Message(Message.ActionTyp.Delete);
    	Question delQuestion = new Question();
		delQuestion.setId(id);
    	msgOut.setQuestion(delQuestion);
    	try {
			msgOut.send(this.client);
		} catch (Exception e) {
			return (false);
		}
    	//Antwort
    	Message msgIn;
    	try {
			msgIn = Message.receive(this.client);
		} catch (Exception e) {
			return(false);
		}
    	if(msgIn.getActionTyp() == Message.ActionTyp.Success)	re = true;
    	else													re = false;
    	
        return (re);
    }
    
    /**
     * Diese Methode hohlt das Hexagramm vom Server, von welchem eine ID uebergeben wurde.
     * Falls das Hexagramm nicht gehohlt werden konnte, wird NULL zurueckgegeben.
     * @param hexId ID des Hexagramms, welche geholt werden konnte
     * @return Das gewuenschte Hexagramm bzw. NULL
     */
    public Hexagram hexagramGet(int hexId){
    	//Senden
    	Message msgOut = new Message(Message.ActionTyp.Get);
    	Hexagram neededHexagram = new Hexagram();
    	neededHexagram.setId(hexId);
    	msgOut.setHexagram(neededHexagram);
    	try {
			msgOut.send(this.client);
		} catch (Exception e) {
			return (null);
		}
    	//Antwort
    	Message msgIn;
    	try {
			msgIn = Message.receive(this.client);
		} catch (Exception e) {
			return(null);
		}
    	if(msgIn.getActionTyp() == Message.ActionTyp.Success){
    		neededHexagram = msgIn.getHexagram();
    	}
    	else{
    		neededHexagram = null;
    	}	
        return (neededHexagram);
    }
    
    //Author Murillo
    /**
     * Diese Methode schickt dem Server ein Hexagramm mit der Aufforderung dieses zu speichern.
     * @param hex Das Hexagramm welches gespeichert werden soll
     * @param Boolean ob der Originaltext des Hexagramms auch geaendert wird
     * @return Boolean ob die Speicherung durchgefuehrt werden konnte
     */
    public boolean hexagramSave(Hexagram hex, boolean oriTxtChange){
    	boolean re = true;
    	//Senden
    	Message msgOut = new Message(oriTxtChange ? Message.ActionTyp.SaveAll : Message.ActionTyp.Save);
    	msgOut.setHexagram(hex);
    	try {
			msgOut.send(this.client);
		} catch (Exception e) {
			return (false);
		}
    	//Antwort
    	Message msgIn;
    	try {
			msgIn = Message.receive(this.client);
		} catch (Exception e) {
			return(false);
		}
    	if(msgIn.getActionTyp() == Message.ActionTyp.Success)	re = true;
    	else													re = false;
    	
        return (re);
    }
    
	//Author Murillo
    /**
     * Diese Methode hohlt alle HexagramCores vom Server. Falls der Vorgang nicht durchgefuehrt werden konnt, wird NULL zurueckgegeben
     * @return ArrayList<HexagramCore> Alle HexagramCores
     */
	public ArrayList<HexagramCore> hexagramCoreGetAll(){
		ArrayList<HexagramCore> answer;
		
		//Senden
		Message msgOut = new Message(Message.ActionTyp.GetAll);
		msgOut.setObjectTyp(Message.ObjectTyp.HexagramCore);
		try {
			msgOut.send(this.client);
		} catch (Exception e) {
			return (null);
		}
		
		//Antwort
		Message msgIn;
		try {
			msgIn = Message.receive(this.client);
		} catch (Exception e) {
			return(null);
		}
		if(msgIn.getActionTyp() == Message.ActionTyp.Success){
			answer = msgIn.getHexagramCoreCollection();
		}
		else{
			answer = null;
		}
		
	    return (answer);
	}
	
	//Author Murillo
	/**
	 * Diese Methode hohlt alle UserCores vom Server. Falls der Vorgang nicht durchgefuehrt werden konnte, wird NULL zurueckgegeben
	 * @return  ArrayList<UserCore> Alle UserCores
	 */
    public ArrayList<UserCore> userCoreGetAll(){
    	ArrayList<UserCore> answer;
    	
    	//Senden
    	Message msgOut = new Message(Message.ActionTyp.GetAll);
    	msgOut.setObjectTyp(Message.ObjectTyp.UserCore);
    	try {
			msgOut.send(this.client);
		} catch (Exception e) {
			return (null);
		}
    	
    	//Antwort
    	Message msgIn;
    	try {
			msgIn = Message.receive(this.client);
		} catch (Exception e) {
			return(null);
		}
    	if(msgIn.getActionTyp() == Message.ActionTyp.Success){
    		answer = msgIn.getUserCoreCollection();
    	}
    	else{
    		answer = null;
    	}
    	
        return (answer);
    }
    
    //Author Murillo
    /**
     * Diese Methode schickt dem Server einen UserId mit der Aufforderung den dazugehoerigen Benutzer zu hohlen.
     * Falls der Benutzer nicht gehohlt werden konnte, wird NULL zurueckgegeben.
     * @param userId BenutzerId des zu hohlenden Benutzers
     * @return Der gewuenschte Benutzer bzw. NULL
     */
    public User userGet(int userId){
    	User answer = new User();
        answer.setId(userId);
    	//Senden
    	Message msgOut = new Message(Message.ActionTyp.Get);
    	msgOut.setUser(answer);
    	try {
			msgOut.send(this.client);
		} catch (Exception e) {
			return (null);
		}
    	//Antwort
    	Message msgIn;
    	try {
			msgIn = Message.receive(this.client);
		} catch (Exception e) {
			return(null);
		}
    	
    	if(msgIn.getActionTyp() == Message.ActionTyp.Success){
    		answer = msgIn.getUser();
    	}
    	else{
    		answer = null;
    	}
    	
        return (answer);
    }
    
    //Author Murillo
    /**
     * Diese Methode schickt dem Server die ID eines Benutzers mit der Aufforderung diesen zu loeschen.
     * @param id ID des zu loeschenden Benutzers
     * @return Boolean ob die Loeschung durchgefuehrt werden konnte
     */
    public boolean userDelete(int id){
    	boolean re = false;
    	//Senden
    	Message msgOut = new Message(Message.ActionTyp.Delete);
    	User delUser = new User();
    	delUser.setId(id);
    	msgOut.setUser(delUser);
    	try {
			msgOut.send(this.client);
		} catch (Exception e) {
			return (false);
		}
    	//Antwort
    	Message msgIn;
    	try {
			msgIn = Message.receive(this.client);
		} catch (Exception e) {
			return(false);
		}
    	if(msgIn.getActionTyp() == Message.ActionTyp.Success)	re = true;
    	else													re = false;
    	
        return (re);
    }
    
    //Author Murillo
    /**
     * Diese Methode schickt dem Server einen Benutzer mit der Aufforderung diese zu speichern.
     * Falls der Benutzer nicht gespeichert werden konnte, wird NULL zurueckgegeben.
     * @param user Der zu speichernde Benutzer
     * @return Der gespeicherte Benutzer (falls er keine ID hatte, besitzt er nun eine) bzw. NULL
     */
    public User userSave(User user){
    	User answer = null;
        
    	//Senden
    	Message msgOut = new Message(Message.ActionTyp.Save);
    	msgOut.setUser(user);
    	try {
			msgOut.send(this.client);
		} catch (Exception e) {
			return (null);
		}
    	//Antwort
    	Message msgIn;
    	try {
			msgIn = Message.receive(this.client);
		} catch (Exception e) {
			return(null);
		}
    	if(msgIn.getActionTyp() == Message.ActionTyp.Success){
    		answer = msgIn.getUser();
    	}
    	else{
    		answer = null;
    	}
    	
        return (answer);
    }
    
    //Author Murillo
    /**
     * Diese Methode schickt dem Server eine Categorie mit der Aufforderung diese zu speichern.
     * Falls die Categorie nicht gespeichert werden konnte, wird NULL zurueckgegeben
     * @param cat Die zu speichernde Kategorie
     * @return Die gespeicherte Kategorie (falls sie keine ID hatte, besitzt sie nun eine) bzw. NULL
     */
    public Category catSave(Category cat){
        Category answer = null;
        
        //Senden
    	Message msgOut = new Message(Message.ActionTyp.Save);
    	ArrayList<Category> catCol = new ArrayList<Category>();
    	catCol.add(cat);
    	msgOut.setCategoryCollection(catCol);
    	try {
			msgOut.send(this.client);
		} catch (Exception e) {
			return (null);
		}
    	//Antwort
    	Message msgIn;
    	try {
			msgIn = Message.receive(this.client);
		} catch (Exception e) {
			return(null);
		}
    	if(msgIn.getActionTyp() == Message.ActionTyp.Success){
    		if(msgIn.getCategoryCollection() != null && msgIn.getCategoryCollection().size() > 0){
    			answer = msgIn.getCategoryCollection().get(0);
    		}
    		else{
    			answer = null;
    		}
    	}
    	else{
    		answer = null;
    	}
    	
        return answer;
    }
    
    //Author Murillo
    /**
     * Diese Methode schickt dem Server eine ID einer Kategorie mit der Aufforderung diese zu loeschen
     * @param id ID der zu loeschenden Kategorie
     * @return Boolean ob die Loeschung durchgefuehrt werden konnte
     */
    public boolean catDelete(int id){
    	boolean re = false;
    	//Senden
    	Message msgOut = new Message(Message.ActionTyp.Delete);
    	Category delCat = new Category();
    	delCat.setId(id);
    	ArrayList<Category> catCol = new ArrayList<Category>();
    	catCol.add(delCat);
    	msgOut.setCategoryCollection(catCol);
    	try {
			msgOut.send(this.client);
		} catch (Exception e) {
			return (false);
		}
    	//Antwort
    	Message msgIn;
    	try {
			msgIn = Message.receive(this.client);
		} catch (Exception e) {
			return(false);
		}
    	if(msgIn.getActionTyp() == Message.ActionTyp.Success)	re = true;
    	else													re = false;
    	
        return (re);
    }
    
    //Author Murillo
    /**
     * Diese Methode hohlt alle Kategorien vom Server, welche dem Benutzer zur verfuegung stehen sollen.
     * Falls der Vorgang nicht durchgefuehrt werden konnte, wird NULL zurueckgegeben.
     * @return ArrayList<Category> mit allen Kategorie bzw. NULL
     */
    public ArrayList<Category> catGet(){
    	ArrayList<Category> catCol = null;
    	//Senden
    	Message msgOut = new Message(Message.ActionTyp.GetAll);
    	msgOut.setObjectTyp(Message.ObjectTyp.Category);
    	try {
			msgOut.send(this.client);
		} catch (Exception e) {
			return (null);
		}
    	//Antwort
    	Message msgIn;
    	try {
			msgIn = Message.receive(this.client);
		} catch (Exception e) {
			return(null);
		}
    	if(msgIn.getActionTyp() == Message.ActionTyp.Success){
    		catCol = msgIn.getCategoryCollection();
    	}
    	else{
    		catCol = null;
    	}
    	
        return (catCol);
    }

}
